<template>
  <div class="three-wrapper">
    <div class="box" ref="box"></div>
    <div class="actions">
      <button @click="addCard">创建2D卡片</button>
      <button @click="clear2DCard">清空2D卡片</button>
    </div>
  </div>
</template>

<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import {
  CSS2DRenderer,
  CSS2DObject
} from 'three/examples/jsm/renderers/CSS2DRenderer'
const clock = new THREE.Clock()
const FPS = 30 // 设置渲染频率为30FBS，也就是每秒调用渲染器render方法大约30次
const renderT = 1 / FPS // 单位秒  间隔多长时间渲染渲染一次
let timeS = 0
export default {
  components: {},
  props: {},
  data() {
    return {
      el: null,
      scene: null,
      camera: null,
      renderer: null,
      css2dRenderer: null,
      controls: null,
      animationFrameId: null,
      css2dObject: null,
      cards: []
    }
  },
  computed: {},
  watch: {},
  created() {},
  mounted() {
    this.el = this.$refs['box']
    this.clock = new THREE.Clock()

    this.initThree()
  },
  activated() {},
  deactivated() {},
  updated() {},
  beforeDestroy() {
    if (this.animationFrameId) {
      cancelAnimationFrame(this.animationFrameId)
    }
  },
  destroyed() {},
  methods: {
    initThree() {
      // 初始化 - 开始
      this.initScene() // 核心： 场景
      this.initCamera() // 核心: 相机
      this.initRender() // 核心 渲染器
      this.initLight()
      this.initControls()
      this.animate()
      this.scene.add(this.setGridHelper(100 * 2, 10 * 2))
      this.scene.add(this.setAxesHelper(100000))
      // 初始化 - 结束

      // 添加物体
      this.addMesh()
    },
    addMesh() {
      const geometry = new THREE.BoxGeometry(10, 10, 10)
      const material = new THREE.MeshLambertMaterial({
        color: new THREE.Color('#00ff00'),
        transparent: true
      })
      const mesh = new THREE.Mesh(geometry, material)
      this.scene.add(mesh)
    },
    addCard() {
      // 创建CSS3D渲染器（如果还没有创建）
      if (!this.css2dRenderer) {
        this.initCSS2DRenderer()
      }
      // 创建卡片的HTML元素
      const cardElement = document.createElement('div')
      cardElement.className = 'css2d-card'
      cardElement.innerHTML = `
          <div class="card-header">
            <h3>CSS3D 卡片</h3>
          </div>
          <div class="card-content">
            <p>这是一个使用 CSS3DRenderer 创建的3D卡片</p>
            <p>位置: (${(Math.random() * 200 - 100).toFixed(1)}, ${(
        Math.random() * 200 -
        100
      ).toFixed(1)}, ${(Math.random() * 200 - 100).toFixed(1)})</p>
          </div>
          <div class="card-footer">
            <button class="card-btn">点击我</button>
          </div>
        `

      // 添加样式
      cardElement.style.width = '200px'
      cardElement.style.padding = '15px'
      cardElement.style.backgroundColor = 'rgba(255, 255, 255, 0.9)'
      cardElement.style.border = '2px solid #409eff'
      cardElement.style.borderRadius = '8px'
      cardElement.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.3)'
      cardElement.style.color = '#333'
      cardElement.style.fontFamily = 'Arial, sans-serif'
      cardElement.style.textAlign = 'center'
      cardElement.style.cursor = 'pointer'
      cardElement.style.transition = 'all 0.3s ease'

      // 创建CSS3D对象
      const css2dObject = new CSS2DObject(cardElement)

      css2dObject.position.set(0, 0, 0)
      this.css2dObject = css2dObject

      // 添加到场景
      this.scene.add(css2dObject)
      this.cards.push(css2dObject) // 👈 记录引用
    },
    initCSS2DRenderer() {
      const width = this.el.offsetWidth
      const height = this.el.offsetHeight

      this.css2dRenderer = new CSS2DRenderer()
      this.css2dRenderer.setSize(width, height)
      this.css2dRenderer.domElement.style.position = 'absolute'
      this.css2dRenderer.domElement.style.top = '0'
      this.css2dRenderer.domElement.style.left = '0'
      this.css2dRenderer.domElement.style.pointerEvents = 'none'

      this.el.appendChild(this.css2dRenderer.domElement)
    },
    clear2DCard() {
      // 从场景中移除所有卡片
      this.cards.forEach(card => {
        this.scene.remove(card)
        // 可选：手动移除 DOM 元素（CSS2DRenderer 通常会自动处理，但显式清理更安全）
        if (card.element && card.element.parentNode) {
          card.element.parentNode.removeChild(card.element)
        }
      })
      // 清空数组
      this.cards = []
    },
    setGridHelper(size, divisions) {
      const gridHelper = new THREE.GridHelper(size, divisions)
      gridHelper.material.opacity = 0.8
      gridHelper.material.transparent = true
      return gridHelper
    },
    setAxesHelper(size) {
      return new THREE.AxesHelper(size)
    },
    // 初始化场景
    initScene() {
      this.scene = new THREE.Scene()
    },
    // 初始化相机
    initCamera() {
      const asp = this.el.offsetWidth / this.el.offsetHeight
      this.camera = new THREE.PerspectiveCamera(45, asp, 0.1, 10000000)
      this.camera.position.set(300, 300, 300)
      this.camera.lookAt(this.scene.position)
      this.scene.add(this.camera)
    },
    initRender(clearColor = '#000') {
      const width = this.el.offsetWidth
      const height = this.el.offsetHeight
      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
      })
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.setSize(width, height)
      this.el.append(this.renderer.domElement)
      // this.renderer.setClearColor(clearColor, 1) // 不设置背景色
    },
    initLight() {
      const ambientLight = new THREE.AmbientLight('#fff', 0.4)
      this.scene.add(ambientLight)
      const directionalLight = new THREE.DirectionalLight('#fff', 0.8)
      directionalLight.position.set(30, 30, 30).normalize()
      this.scene.add(directionalLight)
    },
    initControls() {
      this.controls = new OrbitControls(
        this.camera,
        this.renderer.domElement,
        {}
      )
      // dampingFactor 阻尼系数
      /* 值范围：0 ~ 1
      较小值 (如 0.01)：惯性更大，滑动时间更长
      较大值 (如 0.1)：惯性较小，停止更快
      推荐值：0.05 ~ 0.08 */
      this.controls.enableDamping = true
      this.controls.dampingFactor = 0.05
    },
    render() {
      const dt = this.clock.getDelta()
      const T = clock.getDelta()
      timeS = timeS + T
      if (timeS > renderT) {
        this.controls.update(dt)
        this.renderer.render(this.scene, this.camera)
        if (this.css2dRenderer) {
          this.css2dRenderer.render(this.scene, this.camera)
        }
        timeS = 0
      }
    },
    animate() {
      this.render()
      this.animationFrameId = requestAnimationFrame(this.animate)
    }
  },
  filters: {}
}
</script>
<style scoped lang="scss">
.three-wrapper {
  height: 100%;
  position: relative;
  .box {
    height: 100%;
    width: 100%;
    background: url(./images/map-bg.png);
    background-size: cover;
    background-repeat: no-repeat;
    overflow: hidden;
  }
  .actions {
    position: absolute;
    bottom: 10px;
    left: 10px;
    display: flex;
    gap: 10px;

    button {
      padding: 8px 16px;
      border: none;
      background-color: #409eff;
      color: #fff;
      border-radius: 6px;
      cursor: pointer;
      font-size: 14px;
      transition: all 0.3s ease;

      &:hover {
        background-color: #66b1ff;
        transform: translateY(-2px);
        box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
      }
    }
  }
}

// CSS3D卡片内部样式
::v-deep .css2d-card {
  .card-header {
    margin-bottom: 10px;

    h3 {
      margin: 0;
      color: #409eff;
      font-size: 18px;
    }
  }

  .card-content {
    margin-bottom: 15px;

    p {
      margin: 5px 0;
      font-size: 14px;
      line-height: 1.4;
    }
  }

  .card-footer {
    .card-btn {
      padding: 6px 12px;
      background-color: #409eff;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      font-size: 12px;
      transition: background-color 0.3s;

      &:hover {
        background-color: #66b1ff;
      }
    }
  }
}
</style>
